﻿using System;
using System.Threading;

namespace FizzBuzz
{
    internal class Program
    {
        
        private void Test(int i)
        {
            Thread t = new Thread(TestOverflow, 1024*i);
            t.Start();
        }

        private void TestOverflow(object o)
        {
            int i = (int) o;
            Console.WriteLine("TestOverflow(i={0}", i);
            TestOverflow(i + 1);
        }

        private static void Main()
        {
            // benchmark demo
            var stopwatch = new Benchmark().Report(
                delegate
                    {
                        Console.WriteLine("Inside Action method");
                        Thread.Sleep(2000);
                    }
                );

            Console.WriteLine(stopwatch.Elapsed);

            // linq demo - selecting all assemblies
//            new AssembliesLinq().Run();

            // thread stack overflow test
//            new Program().TestOverflow(1);

//            Thread t = new Thread(() => Console.WriteLine("Hello thread"));
//            t.Start();

            // get the threadpool thread count
//            int workerThreadCont;
//            int completionPortThreads;
//            ThreadPool.GetMaxThreads(out workerThreadCont,out completionPortThreads);
//            ThreadPool.GetAvailableThreads(out workerThreadCont, out completionPortThreads);
//            Console.WriteLine("WorkerThreads:{0} IOThreads:{1}", workerThreadCont, completionPortThreads);

            // using T4 templating engine
//            new HelloT4().HelloWorld();

//            DelegateDemo d = new DelegateDemo();
//            d.Run();
            // looping demo
//            Looping lo = new Looping();
//            lo.Run();

            // sort demo
//            SortDemo sd = new SortDemo();
//            sd.Run();

            // Socket Demo
//            SocketDemo sd = new SocketDemo();
//            sd.Run();
//            System.Console.ReadLine();
            
            // WCFServiceDemo
//            WCFServiceDemo wd = new WCFServiceDemo();
//            wd.Run();

            // effective csharp
            // 1. Prefer readonly over const
            // 2. Value types store data, Reference types store behaviour
            // 3. Prefer Immutable Atomic Value Types - Start with a type with just accessor
            // 4. ReferenceEquals, Equals, Instance.Equals, ==
            // 

            //windsor
//            WindsorTest wt = new WindsorTest();
//            wt.Run();

            // data contract serialization
//            DataContractTest dd = new DataContractTest();
//            dd.Run();

            // linq 
//            LinqRemoteQueriesDemo lrd = new LinqRemoteQueriesDemo();
//            lrd.Run();

//            LinqLocalQueriesDemo ld = new LinqLocalQueriesDemo();
//            ld.Run();

            // extension methods
            // instance methods will always take preference on static method
            // can be applicable on interfaces
//            ExtensionDemo ed = new ExtensionDemo();
//            ed.Run();

            // lambda
//            LambdaDemo ld = new LambdaDemo();
//            ld.Run();

            // events
//            EventsDemo ed = new EventsDemo();
//            ed.Run();

            // Context
            // client always interact with ContextBoundObject with a proxy
            // context bound services: available to context bound objects.
            // Synchronization domain
            // enterprise servers: available for classes derived from ServicedComponent
            // object pooling, transaction
            // context interception is a decorator pattern
//            Console.WriteLine("Thread context:" + Thread.CurrentContext.ContextID);
//            ContextDemo cd = new ContextDemo();
//            cd.Main();

            // Remoting
            // Client -> method call -> proxy -> message -> formatter -> channel
            // Transparent Proxy and RealProxy
//            RemotingDemo rd = new RemotingDemo();
//            rd.Main();

//            UnderTheCovers covers = new UnderTheCovers();
//            covers.Main();

            // AppDomain
            // non-remoteable types
            // MBV: marshal by value: serializeable types
            // create a new copy of the type with the same state as the original
            // MBR: marshal by reference: derive from System.MarshalByRefObject
            // creates a proxy in the desination appdomain. Any calls made to the proxy
            // are transparently passed to the remote application domain and issues the
            // call against the actual object. Results are mashalled back to the caller
//            AppDomainSetupDemo adDemo = new AppDomainSetupDemo();
////            adDemo.Run();
//            adDemo.RunMarshalDemo();

            // Threadpool
            // worker threads: for async executions or timers
            // completion threads: used for network socket processing
            // default max. number of completion port threads is 1000
//            StaticThreadDemo td = new StaticThreadDemo();
//            td.ShowThreadPoolAvailableThreads();
            // custom thread pool:
            // because: default threadpool cannot cancel a queued response
            // implement IBackgroundTaskThreadMarshaller

            // ISynchronizeInvoke
            // provides a way to invoking a method on objects residing on other threads
            // eg. If an object implements ISynchronizeInvoke, the client on Thread T1
            // can call ISynchronize's Invoke() on the object. The implement of Invoke()
            // blocks the calling thread, marshals the call to Thread T2, marshals any
            // return value to Thread T1 and returns control to the calling client on T1.


            // Interlocked
            // accesses a variable in atomic manner

            // Thread relative static variables
//            StaticThreadDemo td = new StaticThreadDemo();

            // WaitHandle
            // - WaitHandle can sync on value and ref types whereas Monitor can only sync on 
            // ref types.
            // - WaitHandle is an abstract class, derived by Mutex
            // - Mutex is process wide. One thread can only acquire a Mutex at a time using WaitOne ... method.
            // - EventWaitHandle is used to signal an event across threads.
            // - ManualResetEvent / AutoResetEvent : EventWaitHandle
            // - For AutoEventReset, we have to set the every time we like to signal
//            EventDemo e_demo = new EventDemo();
//            e_demo.GoThread();
//            Thread.Sleep(1000);
//            e_demo.StopThread();
            // Semaphone - introduced in .NET 2.0
            // designed to control the number of clients trying to access a resource.
            // Interlocked


            // Conditional Attribute class
//            ConditionalAttributeClass cc = new ConditionalAttributeClass();
//            cc.DebugLog("Hello world");

            // Contexts:
            // - Every appdomain starts with a default context.
            // - context is a logical grouping of components (classes)
            // - client never have direct access to the context, it uses a proxy
            // - A set of context bound objects that share is lock is said to be in a
            // synchronization domain.

            // Managed Thread id
            // - suspend/resume is bad because there is no guarantee when these
            // operations will take place. Because of the next safe point the JIT
            // puts in. 
            // - calling sleep(0) is a way to force a thread to context switch.
            // - sleep should only be used in a timer.
            // - SpinWait: like Sleep() but never added to the queue of waiting threads
            // - Always use deterministic programming(synchronisation objects)
            // - Join waits for the other thread to return.
            // - Foreground/Background threads
//            Thread t = Thread.CurrentThread;
//            int id = t.ManagedThreadId;
//            Console.WriteLine("Main Thread ID:{0}", id);
//
//            MyThreadClass tc = new MyThreadClass();
//            ThreadStart ts = new ThreadStart(tc.ShowMessage2);
////            ts += tc.ShowMessage2;
//            Thread t2 = new Thread(ts);
//            t2.Start();
//            Thread.Sleep(2000);
            // Async call using delegates
//            CalculatorTest ctest = new CalculatorTest();
//            ctest.Run();

            // LINQ query test
//            var words = new[] { "the", "quick", "brown"};
//            var query = from x in words
//                        where x.Length > 3
//                        select x.ToUpper();
//
//            foreach(string word in query)
//            {
//                Console.WriteLine(word);
//            }

//            // Delegate event publication/subscription test
//            NewsAgent a = new NewsAgent("A");
//            NewsAgent b = new NewsAgent("B");
//            NewsPublisher p = new NewsPublisher();
//            p.NewsItem += a.NewsHandler;
//            p.NewsItem += b.NewsHandler;
//            p.FireEvent("Election");
//            p.FireEvent("Sports news");
//            Publisher p = new Publisher();
//            Subscriber s = new Subscriber();
//            p.NumberChanged += s.OnNumberChanged;
//
//            p.NumberChanged(3);
//
//            MyClass<int> mc = new MyClass<int>();
//            MyClass<int>.GenericEventHandler del;

//            MyClass obj1 = new MyClass();
//            MyClass obj2 = new MyClass();
//            MyClass obj3 = new MyClass();
//            using(obj1)
//            using(obj2)
//            using(obj3)
//            {
//                obj1.SomeMethod();
//                obj2.SomeMethod();
//                obj3.SomeMethod();
//            }

//            ITrace a = new A();
//            a.TraceSelf();
//
//            ITrace b = new B();
//            b.TraceSelf();
//
//            ITrace c = new C();
//            c.TraceSelf();
//            for (int i = 0; i < 100; i++)
//            {
//                if (i % 3 == 0)
//                {
//                    Console.WriteLine(i + " Fizz");
//                }
//                else if (i % 5 == 0)
//                {
//                    Console.WriteLine(i + " Buzz");
//                }
//
//                if ((i % 3) == 0 && (i % 5)==0)
//                {
//                    Console.WriteLine(i + " FizzBuzz");
//                }
//            }
        }
    }
}